﻿using System;
using System.Windows.Forms;
using GACore;
using GACore.ReversiGA;
using GACore.Structures;

namespace Reversi
{
	public partial class FormGASettings : Form
	{
		private ReversiGAMapper reversiGAMapper;

		private Preferences preferences;
		public Preferences Preferences
		{
			get { return preferences; }
		}

		private string filename;
		public string Filename
		{
			get { return filename; }
			set { filename = value; }
		}

		public FormGASettings(Preferences preferences, string filename)
		{
			InitializeComponent();
			this.preferences = preferences == null ? GetDefaultPreferences() : preferences;
			this.filename = filename;
		}

		private Preferences GetDefaultPreferences()
		{
			preferences = new Preferences();
			preferences.CrossoverProperties = new CrossoverProperties(CrossoverSchema.CrossoverUniform, null);
			preferences.FitnessProperties = new FitnessProperties(FitnessFunctionType.Individual, false);
			preferences.MarriageProperties = new MarriageProperties(SelectionProfiles.BestFitness, SelectionProfiles.BestFitness, 2);
			preferences.MutationProperties = new MutationProperties(0.1, 0.1, MutationScope.Vector, -1.0, 1.0);
			preferences.OptimizationSteps = 100;
			preferences.PopulationCount = 15;
			preferences.IsVerbose = false;
			preferences.ReplacementProperties = new ReplacementProperties(ReplacementSchema.Elitistic, 2);

			return preferences;
		}

		#region Events

		private void FormGASettings_Load(object sender, EventArgs e)
		{
			openFileDialog1.Filter = "XML (*.xml)|*.xml";
			saveFileDialog1.Filter = "XML (*.xml)|*.xml";
			ChangeCrossoverPoints(preferences.CrossoverProperties.CrossoverSchema);
			InitComboBoxes();

			FillForm();
		}

		private void btnLoad_Click(object sender, EventArgs e)
		{
			if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
			{
				try
				{
					this.filename = openFileDialog1.FileName;
					reversiGAMapper = new ReversiGAMapper(filename);
					preferences = reversiGAMapper.LoadGAPreferences();
					FillForm();
				}
				catch (Exception err)
				{
					ErrorHandler.ShowError(err.Message, "Fehler beim Laden der Einstellungen");
				}
			}
		}

		private void btnSave_Click(object sender, EventArgs e)
		{
			if (filename != null)
			{
				saveFileDialog1.FileName = filename;
			}
			if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
			{
				UpdatePreferences();
				reversiGAMapper = new ReversiGAMapper(saveFileDialog1.FileName);
				reversiGAMapper.PersistGAPreferences(preferences);
				this.filename = saveFileDialog1.FileName;
				txtBxFilename.Text = filename;
			}
		}

		private void cmBxRecombination_SelectedIndexChanged(object sender, EventArgs e)
		{
			ChangeCrossoverPoints((CrossoverSchema)Enum.Parse(typeof(CrossoverSchema), cmBxCrossoverSchema.SelectedItem.ToString()));
			FillCrossoverPoints();
		}

		private void cmBxReplacementSchema_SelectedIndexChanged(object sender, EventArgs e)
		{
			ChangeReplacementCounts((ReplacementSchema)Enum.Parse(typeof(ReplacementSchema), cmBxReplacementSchema.SelectedItem.ToString()));
		}

		private void btnOK_Click(object sender, EventArgs e)
		{
			UpdatePreferences();
			this.DialogResult = System.Windows.Forms.DialogResult.OK;
			this.Close();
		}

		private void btnCancel_Click(object sender, EventArgs e)
		{
			this.DialogResult = DialogResult.Cancel;
			this.Close();
		}

		#endregion

		#region Work

		private void InitComboBoxes()
		{
			cmBxCrossoverSchema.Items.AddRange(Enum.GetNames(typeof(CrossoverSchema)));
			cmBxMarriageSchema.Items.AddRange(Enum.GetNames(typeof(SelectionProfiles)));
			cmBxMutationScope.Items.AddRange(Enum.GetNames(typeof(MutationScope)));
			cmBxReplacementSchema.Items.AddRange(Enum.GetNames(typeof(ReplacementSchema)));
			cmBxSelectionSchema.Items.AddRange(Enum.GetNames(typeof(SelectionProfiles)));
		}

		private void ChangeCrossoverPoints(CrossoverSchema crossoverSchema)
		{
			if (crossoverSchema == CrossoverSchema.Crossover1Point
				|| crossoverSchema == CrossoverSchema.Crossover2Point)
			{
				if (!grpBxPopulation.Controls.Contains(pnlCrossover1Point))
				{
					grpBxPopulation.Controls.Add(pnlCrossover1Point);
				}
				if (crossoverSchema == CrossoverSchema.Crossover1Point)
				{
					if (pnlCrossover1Point.Controls.Contains(pnlCrossover2Point))
					{
						pnlCrossover1Point.Controls.Remove(pnlCrossover2Point);
					}
				}
				else if (crossoverSchema == CrossoverSchema.Crossover2Point)
				{
					if (!pnlCrossover1Point.Controls.Contains(pnlCrossover2Point))
					{
						pnlCrossover1Point.Controls.Add(pnlCrossover2Point);
					}
				}
			}
			else
			{
				if (grpBxPopulation.Controls.Contains(pnlCrossover1Point))
				{
					grpBxPopulation.Controls.Remove(pnlCrossover1Point);
				}
			}
		}

		private void FillForm()
		{
			cmBxCrossoverSchema.SelectedItem = preferences.CrossoverProperties.CrossoverSchema.ToString();
			cmBxMarriageSchema.SelectedItem = preferences.MarriageProperties.MarriageSchema.ToString();
			cmBxMutationScope.SelectedItem = preferences.MutationProperties.MutationScope.ToString();
			cmBxReplacementSchema.SelectedItem = preferences.ReplacementProperties.Schema.ToString();
			cmBxSelectionSchema.SelectedItem = preferences.MarriageProperties.SelectionSchema.ToString();

			nUDCountReplacements.Value = preferences.ReplacementProperties.ReplacementCount;
			nUDCountSelectedVectors.Value = preferences.MarriageProperties.CountOfSelectedVectors;
			nUDCrossoverPointsThrough.Value = preferences.CrossoverProperties.CrossoverPoints != null ? preferences.CrossoverProperties.CrossoverPoints[0] : 0;
			nUDCrossoverPointsFrom.Value = preferences.CrossoverProperties.CrossoverPoints != null && preferences.CrossoverProperties.CrossoverPoints.Length == 2 ? preferences.CrossoverProperties.CrossoverPoints[1] : 0;
			nUDLimitsMaximum.Value = (decimal)(double)preferences.MutationProperties.MaxValue;
			nUDLimitsMinimum.Value = (decimal)(double)preferences.MutationProperties.MinValue;
			nUDMutationRate.Value = (decimal)preferences.MutationProperties.MutationRate;
			nUDMutationWidth.Value = (decimal)(double)preferences.MutationProperties.MutationWidth;
			nUDPopulationCount.Value = preferences.PopulationCount;
			nUDCountOptSteps.Value = preferences.OptimizationSteps;
			chckBxVerbose.Checked = preferences.IsVerbose;

			txtBxFilename.Text = filename;
		}

		private void FillCrossoverPoints()
		{
			if (preferences.CrossoverProperties.CrossoverSchema == CrossoverSchema.Crossover1Point)
			{
				nUDCrossoverPointsThrough.Value = 0;
				if (preferences.CrossoverProperties.CrossoverPoints != null)
				{
					nUDCrossoverPointsThrough.Value = preferences.CrossoverProperties.CrossoverPoints[0];
				}
			}
			else if (preferences.CrossoverProperties.CrossoverSchema == CrossoverSchema.Crossover2Point)
			{
				nUDCrossoverPointsThrough.Value = 0;
				nUDCrossoverPointsFrom.Value = 1;

				if (preferences.CrossoverProperties.CrossoverPoints != null && preferences.CrossoverProperties.CrossoverPoints.Length == 2)
				{
					nUDCrossoverPointsThrough.Value = preferences.CrossoverProperties.CrossoverPoints[0];
					nUDCrossoverPointsFrom.Value = preferences.CrossoverProperties.CrossoverPoints[1];
				}
			}
		}

		private void ChangeReplacementCounts(ReplacementSchema replacementSchema)
		{
			if (replacementSchema == ReplacementSchema.NotElitistic || replacementSchema == ReplacementSchema.Elitistic)
			{
				if (grpBxReplacement.Controls.Contains(pnlReplacementCount))
				{
					grpBxReplacement.Controls.Remove(pnlReplacementCount);
				}
			}
			else
			{
				if (!grpBxReplacement.Controls.Contains(pnlReplacementCount))
				{
					grpBxReplacement.Controls.Add(pnlReplacementCount);
				}
			}
		}

		private void UpdatePreferences()
		{
			preferences.CrossoverProperties.CrossoverSchema = (CrossoverSchema)Enum.Parse(typeof(CrossoverSchema), cmBxCrossoverSchema.SelectedItem.ToString());
			preferences.MarriageProperties.MarriageSchema = (SelectionProfiles)Enum.Parse(typeof(SelectionProfiles), cmBxMarriageSchema.SelectedItem.ToString());
			preferences.MutationProperties.MutationScope = (MutationScope)Enum.Parse(typeof(MutationScope), cmBxMutationScope.SelectedItem.ToString());
			preferences.ReplacementProperties.Schema = (ReplacementSchema)Enum.Parse(typeof(ReplacementSchema), cmBxReplacementSchema.SelectedItem.ToString());
			preferences.MarriageProperties.SelectionSchema = (SelectionProfiles)Enum.Parse(typeof(SelectionProfiles), cmBxSelectionSchema.SelectedItem.ToString());

			preferences.ReplacementProperties.ReplacementCount = Convert.ToInt32(nUDCountReplacements.Value);
			preferences.MarriageProperties.CountOfSelectedVectors = Convert.ToInt32(nUDCountSelectedVectors.Value);

			if (preferences.CrossoverProperties.CrossoverSchema == CrossoverSchema.CrossoverUniform)
			{
				preferences.CrossoverProperties.CrossoverPoints = null;
			}
			else if (preferences.CrossoverProperties.CrossoverSchema == CrossoverSchema.Crossover1Point)
			{
				preferences.CrossoverProperties.CrossoverPoints = new int[] { Convert.ToInt32(nUDCrossoverPointsThrough.Value) };
			}
			else
			{
				preferences.CrossoverProperties.CrossoverPoints = new int[] { Convert.ToInt32(nUDCrossoverPointsThrough.Value), Convert.ToInt32(nUDCrossoverPointsFrom.Value) };
			}

			preferences.MutationProperties.MaxValue = Convert.ToDouble(nUDLimitsMaximum.Value);
			preferences.MutationProperties.MinValue = Convert.ToDouble(nUDLimitsMinimum.Value);
			preferences.MutationProperties.MutationRate = Convert.ToDouble(nUDMutationRate.Value);
			preferences.MutationProperties.MutationWidth = Convert.ToDouble(nUDMutationWidth.Value);
			preferences.PopulationCount = Convert.ToInt32(nUDPopulationCount.Value);
			preferences.OptimizationSteps = Convert.ToInt32(nUDCountOptSteps.Value);
			preferences.IsVerbose = chckBxVerbose.Checked;

			filename = txtBxFilename.Text;
		}

		#endregion

	}
}
